'''
Created on 2009-11-18

@author: yuchen
'''

import ai.abstract_player
import interface.ConsoleAgent as itfc
import gamemodel.SubNeighborhood5x5 as mNB
import re
import math
import random
import sys

class AIcomputer(ai.abstract_player.AIPlayer):
	
	def __init__(self, player):
		ai.abstract_player.AIPlayer.__init__(self, player)
		self.tempoPiece = [None, None, None, None]
		self.player = [None, None]
		self.tempoState = 1
		self.drawCondition1 = [0, 0, 0, 0]
		self.drawCondition2 = 0
		self.drawCondition3 = [0, 0]
		
	def get_move(self, state):
		# get all moves
		
		moves = state.successorMove()				 
		if moves == None :						 
			return None
		elif len(moves) == 1:
			return moves[0]
		
		if self.get_draw(state) == True :
			return 'draw'
		
		height = 6
		heuristicNumber = self.get_heurisitc(state, height)
				
		return moves[heuristicNumber]
	
	def get_draw(self, state):
		moves = state.successorMove()
		player = state.getCurrentPlayer()
		if self.player[0] == None :
			self.player[0] = state.board.getPlayer0()
			self.player[1] = state.board.getPlayer1()
			number = 0
		else :
			if self.player[0] == player :
				number = 0
			else :
				number = 1
				
		# judge whether a state has been repeated 3 times
		self.tempoState = 1 - self.tempoState
		tempPiece0 = []
		tempPiece1 = []
		for piece in self.player[number].pieces :
			tempPiece0.append(piece.position)
		tempPiece0.sort()
		
		for piece in self.player[1 - number].pieces :
			tempPiece1.append(piece.position)
		tempPiece1.sort()
		
		if self.tempoPiece[number + 2 * self.tempoState] == None :
			self.tempoPiece[number + 2 * self.tempoState] = tempPiece0
			self.tempoPiece[1 - number + 2 * self.tempoState] = tempPiece1
			self.drawCondition1[number + 2 * self.tempoState] += 1
		else :
			if self.tempoPiece[number + 2 * self.tempoState] == tempPiece0 and\
			self.tempoPiece[1 - number + 2 * self.tempoState] == tempPiece1 :
				self.drawCondition1[number + 2 * self.tempoState] += 1
			else :
				self.tempoPiece[number + 2 * self.tempoState] = tempPiece0
				self.tempoPiece[1 - number + 2 * self.tempoState] = tempPiece1
				self.drawCondition1[number + 2 * self.tempoState] = 1
		
		if self.drawCondition1[number + 2 * self.tempoState] == 3 :
			return True
		
		# only move king and do not eat any piece in 25 turns
		currentPiece = state.board.getBoardPosition(moves[number].list[0].original[0], moves[number].list[0].original[1], player)
		if currentPiece.king == True and\
		abs(moves[number].list[0].original[0] - moves[number].list[0].destination[0]) == 1 and\
		abs(moves[number].list[0].original[1] - moves[number].list[0].destination[1]) == 1 :
			self.drawCondition2 += 1
		else :
			self.drawCondition2 = 0
		
		if self.drawCondition2 == 50 :
			return True
		
		# if one player have less than 3 pieces, and the other one player has only one king in 16 turns.
		if len(tempPiece0) <= 3 and len(tempPiece1) == 1 :
			if self.player[1 - number].pieces.king == True :
				self.drawCondition3[number] += 1
		
		if self.drawCondition3[number] == 16 :
			return True
		
		return False

	def get_heurisitc(self, currentState, height):
		state = currentState.get_copy()
		states = state.Successor()
		height = height - 1
		evaluatedValues = []
		if state != None :
			for state in states :
				evaluatedValues.append(self.get_evaluation(state, height))
		else :
			return -1000						  
		
		evaluatedValue = []
		maxValue = None
		counter = 0
		choiceList = []
		for counter in range(len(evaluatedValues)):
			evaluatedValue = evaluatedValues[counter]
			if maxValue == None :
				maxValue = evaluatedValue
				choiceList.append(counter)
			else :
				if maxValue == evaluatedValue :
					choiceList.append(counter)
				if maxValue > evaluatedValue :
					maxValue = evaluatedValue
					choiceList = []
					choiceList.append(counter)
		
		if len(choiceList) == 1 and height == 5:
			return choiceList[0]
		else :
			if len(choiceList) == 1 or height == 0:
				return  maxValue
			else : 
				state.switchPlayer()
				value = {}
				minMaxValue = None
				if choiceList != None :
					for number in choiceList :
						value[number] = self.get_heurisitc(states[number], height)
				if height != 5 :
					for x in value:
						if minMaxValue == None:
							minMaxValue = x
						else :
							if height % 2 == 0: 
								if minMaxValue < x:
									minMaxValue = x
							else :
								if minMaxValue > x:
									minMaxValue = x
					return minMaxValue
				else :
					returnedValue = []
					for number in choiceList :
						if minMaxValue == None:
							minMaxValue = value[number]
							returnedValue.append(number)
						else :
							if minMaxValue == value[number]:
								returnedValue.append(number)
							if minMaxValue > value[number] :
								minMaxValue = value[number]
								returnedValue = []
								returnedValue.append(number)
					if len(returnedValue) != 1 :
						return random.choice(returnedValue)
					else :
						return returnedValue[0]
			
	def get_evaluation(self, state, height):
		board = state.getBoard()
		player = state.getCurrentPlayer()
		if player == board.getPlayer0() :
			otherPlayer = board.getPlayer1()
		else :
			otherPlayer = board.getPlayer0()
		
		evaluatedValue = EvaluationElements()
		evaluatedValue.state = state
		evaluatedValue.board = board
		evaluatedValue.player = player
		evaluatedValue.otherPlayer = otherPlayer
		
		moves = state.successorMove()				 
		if moves == None :
			evaluatedValue.isLose = True
		
#		# Evaluation criteria:
#		#1. the amount of pieces belongs to the current player
#		evaluatedValue.piece_amount()
#		#2. the amount of kings belongs to the current player
#		evaluatedValue.king_amount()
#		
#		#3. the difference of the pieces between the two players
#		evaluatedValue.piece_difference()
#		#4. the difference of the kings between the two players
#		evaluatedValue.king_difference()
#		
#		
#		#5. the average position of all the pieces' Y-Axis
#		#   if it exists some pieces
#		# NOTE : It is the position of PIECE, not including KING
#		evaluatedValue.currentAverage_Y()
#		#6. the Agglomeration of the pieces' Y-Axis
#		#   if it exists some pieces
#		# NOTE : It is the position of PIECE, not including KING
#		evaluatedValue.currentAgglomeration_Y()
#		#7. the Agglomeration of the pieces' X-Axis to the center,
#		#   whose value is 4.5, if it exists some pieces
#		# NOTE : It is the position of PIECE, not including KING
#		evaluatedValue.currentAgglomeration_X()
#		
#		
#		#8. the average position of all the opponent pieces' Y-Axis
#		#   if it exists some pieces
#		# NOTE : It is the position of PIECE, not including KING
#		evaluatedValue.opponentAverage_Y()
#		#9. the Agglomeration of the opponent pieces' Y-Axis
#		#   if it exists some pieces
#		# NOTE : It is the position of PIECE, not including KING
#		evaluatedValue.opponentAgglomeration_Y()
#		#10. the Agglomeration of the opponent pieces' X-Axis to the center,
#		#   whose value is 4.5, if it exists some pieces
#		# NOTE : It is the position of PIECE, not including KING
#		evaluatedValue.opponentAgglomeration_X()
		
		#11. isLose:				 
		if state.successorMove() == None :						 
			evaluatedValue.isLose = True
		
		#last: Calculate the total value:
		if height < 2 :
			return evaluatedValue.calculateTotalValue()
		else :
			return evaluatedValue.calculateFirstValue()
#		return evaluatedValue.totalValue
	
class EvaluationElements(object):
	
	def __init__(self):
		self.player = None
		self.otherPlayer = None
		self.state = None
		self.board = None
		
#		self.pieceAmount = 0
#		self.kingAmount = 0
#		self.pieceDifference = 0
#		self.kingDifference = 0
#		
#		self.currentAverageY = 0
#		self.currentAgglomerationY = 0
#		self.currentAgglomerationX = 0
#		
#		self.opponentAverageY = 0
#		self.opponentAgglomerationY = 0
#		self.opponentAgglomerationX = 0
		
		self.isLose = False
#		self.totalValue = 0
	
	def piece_amount(self) :
#		self.pieceAmount = self.player.piece_count - 1
		return self.player.piece_count - 1
		
	def king_amount(self) :
#		self.kingAmount =  self.player.king_count
		return self.player.king_count
	
	def piece_difference(self):
#		self.pieceDifference = self.piece_amount() - self.otherPlayer.piece_count
		return self.piece_amount() - self.otherPlayer.piece_count
		
	def king_difference(self):
#		self.kingAmount =  self.player.king_count - self.otherPlayer.king_count
		return self.player.king_count - self.otherPlayer.king_count
	
	def currentAverage_Y(self) :
		if self.piece_amount() != 0 :
			pieces = self.player.pieces
			totalValue = 0
			for piece in pieces :
				if piece.king != True :
					totalValue = totalValue + piece.position[1]
				else :
					totalValue = totalValue + 15 - abs(piece.position[1] - 4.5)
					#+ 4.5 * 1 / abs(piece.position[1] - 4.5)
#			self.currentAverageY = totalValue / ((self.pieceAmount + self.kingAmount)* 1.0)
			return totalValue / ((self.piece_amount() + self.king_amount())* 1.0)
	
	def currentAgglomeration_Y(self) :
		if self.piece_amount() != 0 :
			pieces = self.player.pieces
			caching = 0
			for piece in pieces :
				if piece.king != True :
					caching = caching + (piece.position[1] - self.currentAverage_Y()) ** 2
#			self.currentAgglomerationY = math.sqrt(caching / (self.pieceAmount * 1.0) )
			return math.sqrt(caching / (self.piece_amount() * 1.0) )
	
	def currentAgglomeration_X(self) :
		if self.piece_amount() != 0 :
			pieces = self.player.pieces
			caching = 0
			for piece in pieces :
				if piece.king != True :
					caching = caching + (piece.position[0] - 4.5) ** 2
#			self.currentAgglomerationX = math.sqrt(caching / (self.player.piece_count * 1.0) )
			return  math.sqrt(caching / (self.player.piece_count * 1.0) )
	
	def opponentAverage_Y(self) :
		if self.otherPlayer.piece_count != 0 :
			pieces = self.otherPlayer.pieces
			totalValue = 0
			for piece in pieces :
				if piece.king != True :
					totalValue = totalValue + piece.position[1]
				else :
					totalValue = totalValue + 10 + 4.5 * 1 / abs(piece.position[1] - 4.5)
#			self.opponentAverageY = totalValue / (self.otherPlayer.piece_count * 1.0)
			return totalValue / (self.otherPlayer.piece_count * 1.0)
	
	def opponentAgglomeration_Y(self) :
		if self.otherPlayer.piece_count != 0 :
			pieces = self.otherPlayer.pieces
			caching = 0
			for piece in pieces :
				if piece.king != True :
					caching = caching + (piece.position[1] - self.opponentAverage_Y()) ** 2
#			self.opponentAgglomerationY = math.sqrt(caching / (self.otherPlayer.piece_count * 1.0) )
			return math.sqrt(caching / (self.otherPlayer.piece_count * 1.0) )
	
	def opponentAgglomeration_X(self) :
		if self.otherPlayer.piece_count != 0 :
			pieces = self.otherPlayer.pieces
			caching = 0
			for piece in pieces :
				if piece.king != True :
					caching = caching + (piece.position[0] - 4.5) ** 2
#			self.opponentAgglomerationX = math.sqrt(caching / (self.otherPlayer.piece_count * 1.0) )
			return math.sqrt(caching / (self.otherPlayer.piece_count * 1.0) )
	
	def calculateFirstValue(self):
#		self.totalValue = self.pieceDifference + self.kingDifference * 2.5 - (self.pieceAmount + self.kingAmount * 2.5) * 0.01
		if self.isLose == True :
			return -1000
		else :
			return 100 + self.piece_difference() + self.king_difference() * 4 - self.opponentAverage_Y() * 0.01 + self.currentAverage_Y() * 0.01\
		 - (self.otherPlayer.piece_count + self.otherPlayer.king_count * 4) * 0.001 + (self.currentAgglomeration_Y() - self.opponentAgglomeration_Y()) * 0.002\
		
	
	def calculateTotalValue(self):
#		self.totalValue = self.pieceDifference + self.king_amount() * 2.5 - (self.player.piece_count + self.king_amount() * 2.5) * 0.01\
#		 + self.currentAverageY * 0.001 + (self.currentAgglomerationY - self.opponentAgglomerationY) * 0.0002 +\
#		 (self.opponentAgglomerationX - self.currentAgglomerationX) * 0.0002
		
		if self.isLose == True :
			return -1000
		else :
			return 100 + self.piece_difference() + self.king_difference() * 4 - self.opponentAverage_Y() * 0.01 + self.currentAverage_Y() * 0.01\
		 - (self.otherPlayer.piece_count + self.otherPlayer.king_count * 4) * 0.001 + (self.currentAgglomeration_Y() - self.opponentAgglomeration_Y()) * 0.002\
		 - (self.piece_amount() + self.king_amount() * 2.5) * 0.001
#		(self.opponentAgglomeration_X() - self.currentAgglomeration_X()) * 0.0002
	